package com.kuizii.demo;

import org.springframework.util.ClassUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.StandardOpenOption;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;

public class DemoClassLoader extends ClassLoader {

    static String algorithm = "AES/ECB/PKCS5Padding";

    String key;

    String classPath;

    public DemoClassLoader(String classPath, String securityKey) {
        this.classPath = classPath;
        this.key = securityKey;
    }


    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {

        File file = new File(this.classPath + name.replace(".", "\\") + ".xclass");
        if (file.isFile() && file.getPath().endsWith(".xclass")) {
            try {
                //从JVM中查找是否有加载过该类
                Class<?> loadedClass = findLoadedClass(name);
                if (loadedClass != null) {
                    return loadedClass;
                }
                //否则自行解码class
                byte[] bytes = new byte[(int) file.length()];
                //将缓冲区的数据存放在byte数组中，bytes数组或buff缓冲区任何一方中数据的改动都会影响另一方
                ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
                FileChannel fileChannel = FileChannel.open(file.toPath(), StandardOpenOption.READ);
                while (fileChannel.read(byteBuffer) != -1) {
                    byteBuffer.flip();
                }
                KeyGenerator kgen = KeyGenerator.getInstance("AES");
                kgen.init(128, new SecureRandom(key.getBytes()));
                SecretKey secretKey = kgen.generateKey();
                byte[] enCodeFormat = secretKey.getEncoded();

                Cipher cipher = Cipher.getInstance(algorithm);
                cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(enCodeFormat, "AES"));

                byte[] decode = Base64.getDecoder().decode(bytes);
                byte[] bytes2 = cipher.doFinal(decode);
                loadedClass = defineClass(name, bytes2, 0, bytes2.length);

                return loadedClass;
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            Class<?> systemClass = findSystemClass(name);
            if (systemClass != null) {
                return systemClass;
            }
        }

        return super.loadClass(name);
    }


}
